package com.white.loggerserver.core;

import org.jetbrains.annotations.NotNull;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by ytf on 2019/5/26 026.
 * Description:
 */
public class WatchDog
{
    private long mills;
    private boolean isOnRunning;
    private volatile AtomicBoolean isExit = new AtomicBoolean(false);
    private final byte[] lock = new byte[0];
    private ExecutorService single = Executors.newSingleThreadExecutor();

    private String name;

    public WatchDog(int seconds, String name)
    {
        mills = seconds * 1000;
        this.name = name;
    }

    public WatchDog(float seconds, String name)
    {
        mills = (long) (seconds * 1000);
        this.name = name;
    }

    public boolean isOnRunning()
    {
        return isOnRunning;
    }

    public void start(Callback callback)
    {
        if(!isOnRunning)
        {
            isOnRunning = true;
            isTouch.set(false);
            isExit.set(false);
            single.submit(new Task(callback));
        }
    }

    private class Task implements Runnable{

        private Callback callback;

        public Task(Callback callback) {
            this.callback = callback;
        }

        @Override
        public void run() {
            while (!isExit.get())
            {
                try
                {
                    synchronized (lock)
                    {
                        lock.wait(mills);

                        if(isTouch.get())
                        {
                            isTouch.set(false);
                        }else
                        {
                            if(!isExit.get() && isOnRunning){
                                callback.onTimeout();
                            }
                        }
                    }
                } catch (InterruptedException e)
                {
                    isExit.set(true);
                }
            }
            isOnRunning = false;
        }
    }

    private AtomicBoolean isTouch = new AtomicBoolean(false);
    public void touch()
    {
        if(isOnRunning)
        {
            synchronized (lock)
            {
                isTouch.set(true);
                lock.notify();
            }
        }
    }

    public void stop()
    {
        synchronized (lock){
            isExit.set(true);
            isOnRunning = false;
            lock.notify();
        }
    }

    public interface Callback
    {
        void onTimeout();
    }

    @NotNull
    @Override
    public String toString()
    {
        return name;
    }
}
